﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Configuration;
using System.IO;
using System.Reflection;
using System.Threading;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media.Imaging;
using System.Windows.Threading;
using Microsoft.Office.Server;
using Microsoft.Office.Server.UserProfiles;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Utilities;
using SPContentCreator.Code;

namespace SPContentCreator
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow
    {
        private bool _isSiteLoaded;
        private Site _site;

        public MainWindow()
        {
            InitializeComponent();

            LoadFileTypes();
            #if DEBUG
              LoadSite("http://intranet");
            #endif
        }

        ~MainWindow()
        {
        }

        private void PopulateSiteData()
        {
            SPWebTemplateCollection templates = _site.spWeb.GetAvailableWebTemplates(1033);
            foreach (SPWebTemplate template in templates)
            {
                availableSiteTemplatesListBox.Items.Add(template.Name);
            }

            LoadDocumentLibraries(false);
            LoadLists(false);
        }

        #region Unimplemented
        private void dateRangeCheckBox_Checked(object sender, RoutedEventArgs e)
        {

        }

        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
        }

        private void methodComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
        }

        private void checkBox1_Checked(object sender, RoutedEventArgs e)
        {
        }

        private void numberOfSitesTextBox_TextChanged(object sender, TextChangedEventArgs e)
        {
        }

        private void listBox1_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
        }

        private void textBox1_TextChanged(object sender, TextChangedEventArgs e)
        {
        }

        private void textBox2_TextChanged(object sender, TextChangedEventArgs e)
        {
        }



        private void numberOfFilesTextBox_TextChanged(object sender, TextChangedEventArgs e)
        {
        }

        private void image1_ImageFailed(object sender, ExceptionRoutedEventArgs e)
        {
        }

        #endregion

        #region Utility/Helper Functions
        

        private BitmapImage GetIconImage(string imageName)
        {
            var bitmap = new BitmapImage(new Uri(@"pack://application:,,,/"
                                                 + Assembly.GetExecutingAssembly().GetName().Name
                                                 + ";component/"
                                                 + "Icons/" + imageName, UriKind.Absolute));
            return bitmap;
        }

        private void StatusWarning()
        {
            statusImage.Source = GetIconImage("warning.png");
        }

        private void StatusGood()
        {
            statusImage.Source = GetIconImage("good.png");
        }

        private void StatusBad()
        {
            statusImage.Source = GetIconImage("error.png");
        }

        private int GetFileSizeUnitMultiplier()
        {
            int result;
            ComboBoxItem selectedItem = (ComboBoxItem) fileSizeUnitComboBox.SelectedItem;
            switch(selectedItem.Content.ToString())
            {
                case "MB":
                    result = 1048576;
                    break;
                case "KB":
                    result = 1024;
                    break;
                default:
                    result = 1;
                    break;
            }

            return result;
        }

        private void Log(string message, MessageType messageType)
        {
            string output = string.Format("[{0}][{1}]:{2}\r\n", messageType.ToString(), DateTime.Now.ToString("h:mm:ss"),
                                          message);
            if (outputTextBox.Dispatcher.Thread != Thread.CurrentThread)
            {
                outputTextBox.Dispatcher.Invoke((ThreadStart) delegate
                                                                  {
                                                                      outputTextBox.AppendText(output);
                                                                      outputTextBox.ScrollToEnd();
                                                                  });
            }
            else
            {
                outputTextBox.AppendText(output);
                outputTextBox.ScrollToEnd();
            }
        }

        private void ClearControls()
        {
            availableSiteTemplatesListBox.Items.Clear();
            documentLibrariesListBox.Items.Clear();
            listsListBox.Items.Clear();
        }

        private void GenerateItemData(SPListItem item)
        {
            SPFieldCollection fields = item.Fields;
            foreach (SPField field in fields)
            {
                if(!field.Hidden && !field.ReadOnlyField)
                {
                    var type = field.Type;
                    if(type == SPFieldType.Text)
                    {
                        GenerateTextData(item, field as SPFieldText);
                    }
                    if(type == SPFieldType.Note)
                    {
                        GenerateMultiLineTextData(item, field as SPFieldMultiLineText);
                    }
                    if(type == SPFieldType.Number)
                    {
                        GenerateNumberData(item, field as SPFieldNumber);
                    }
                    if(type == SPFieldType.Choice)
                    {
                        GenerateChoiceData(item, field as SPFieldChoice);
                    }
                    if(type == SPFieldType.DateTime)
                    {
                        GenerateDateTimeData(item, field as SPFieldDateTime);
                    }
                    if(type == SPFieldType.Boolean)
                    {
                        GenerateBooleanData(item, field as SPFieldBoolean);
                    }
                    if(type == SPFieldType.Lookup)
                    {
                        GenerateLookupData(item, field as SPFieldLookup);
                    }
                    if(type == SPFieldType.URL)
                    {
                        GenerateUrlData(item, field as SPFieldUrl);
                    }
                    if(type == SPFieldType.User)
                    {
                        GenerateUserData(item, field as SPFieldUser);
                    }
                }
            }
        }

        private void GenerateLookupData(SPListItem item, SPFieldLookup field)
        {
            using(SPWeb web = _site.spSite.AllWebs[field.LookupWebId])
            {
                SPList lookupList = web.Lists[new Guid(field.LookupList)];
                SPListItemCollection lookupListItems = lookupList.Items;

                var random = new Random();
                SPListItem randomItem = lookupListItems[random.Next(0, lookupListItems.Count)];

                var lookupItem = new SPFieldLookupValue(randomItem.ID, randomItem[field.LookupField].ToString());
                item[field.Id] = lookupItem;
            }
        }

        private void GenerateUrlData(SPListItem item, SPFieldUrl field)
        {
            var random = new Random();
            var url = new SPFieldUrlValue();
            url.Description = Ipsum.GetWords(random.Next(0,3));
            url.Url = _site.spWeb.Url;
            item[field.Id] = url;
        }

        private void GenerateUserData(SPListItem item, SPFieldUser field)
        {
            SPUserCollection users = _site.spSite.RootWeb.AllUsers;
            var random = new Random();
            int randomUserIndex = random.Next(0, users.Count);
            SPUser user = users[randomUserIndex];
            item[field.Id] = user;
        }

        private void GenerateBooleanData(SPListItem item, SPFieldBoolean field)
        {
            var random = new Random();
            var result = random.Next()%2;
            item[field.Id] = result;
        }

        private void GenerateDateTimeData(SPListItem item, SPFieldDateTime field)
        {
            var dateTime = Utils.RandomDay(356, 356);
            item[field.Id] = dateTime;
        }

        private void GenerateChoiceData(SPListItem item, SPFieldChoice field)
        {
            var choices = field.Choices;
            var random = new Random();
            var choice = choices[random.Next(0, choices.Count - 1)];
            // TODO: MULTI SELECT
            item[field.Id] = choice;
        }

        private void GenerateNumberData(SPListItem item, SPFieldNumber field)
        {
            var random = new Random();

            double minValue = 0;
            if (field.MinimumValue != double.MinValue)
                minValue = field.MinimumValue;

            double maxValue = 100;
            if (field.MaximumValue != double.MaxValue)
                maxValue = field.MaximumValue;

            var data = random.NextDouble()*(maxValue - minValue) + minValue;
            item[field.Id] = data;
        }

        private void GenerateMultiLineTextData(SPListItem item, SPFieldMultiLineText field)
        {
            var data = Ipsum.GetSentence(5);
            item[field.Id] = data;
        }

        private void GenerateTextData(SPListItem item, SPFieldText field)
        {
            var data = Ipsum.GetWords(5);
            item[field.Id] = data;
        }


        #endregion

        #region Create Functions

        private void CreateSites()
        {
            int numberOfSites = Convert.ToInt32(numberOfSitesTextBox.Text);
            for (int i = 0; i < numberOfSites; i++)
            {
            }
        }

        private void CreateDocuments()
        {
            foreach (var documentLibrariesListBoxItem in documentLibrariesListBox.SelectedItems)
            {
                SPFolder docLib = _site.spWeb.Folders[documentLibrariesListBoxItem.ToString()];

                List<string> selectedFileTypes = new List<string>();
                foreach (CheckBox checkBox in fileTypesListBox.Items)
                {
                    if (checkBox.IsChecked == true || useAllTypesCheckBox.IsChecked == true)
                    {
                        selectedFileTypes.Add(checkBox.Content.ToString());
                    }
                }

                var numberOfFiles = Convert.ToInt32(numberOfFilesTextBox.Text);
                for (int i = 0; i < numberOfFiles; i++)
                {
                    var ext = selectedFileTypes[i % selectedFileTypes.Count];
                    var fileName = string.Format("temp{0}.{1}", i, ext);
                    ulong fileSize = Convert.ToUInt64(fileSizeTexBox.Text) * (ulong)GetFileSizeUnitMultiplier();
                    SPFile spfile = docLib.Files.Add(fileName, new byte[fileSize], true);
                    docLib.Update();

                    // Upload document
                    var lastModified = DateTime.Now;
                    if (dateRangeCheckBox.IsChecked == true)
                    {
                        if (endDatePicker.SelectedDate.HasValue && startDatePicker.SelectedDate.HasValue)
                        {
                            TimeSpan timeSpan =
                                endDatePicker.SelectedDate.Value.Subtract(startDatePicker.SelectedDate.Value);
                            Random rand = new Random();
                            double randNumber = rand.Next(-timeSpan.Days, 0);
                            lastModified = DateTime.Now.AddDays(randNumber);
                        }
                    }
                    else
                    {
                        if (fileDatePicker.SelectedDate.HasValue)
                        {
                            lastModified = fileDatePicker.SelectedDate.Value;
                        }
                    }

                    spfile.Item[SPBuiltInFieldId.Modified] =
                        SPUtility.CreateISO8601DateTimeFromSystemDateTime(
                            lastModified.ToUniversalTime());
                    spfile.Item.UpdateOverwriteVersion();

                    var message = string.Format("Added file '{0}' to '{1}'", fileName, docLib.Name);
                    Log(message, MessageType.Info);
                }
            }
        }

        private void CreateListItems()
        {
            foreach (var listListBoxItem in listsListBox.SelectedItems)
            {
                SPList list = _site.spWeb.Lists.TryGetList(listListBoxItem.ToString());
                if(list != null)
                {
                    var numberOfItems = Convert.ToInt32(numberOfListItemsTextBox.Text);
                    for (int i = 0; i < numberOfItems; i++)
                    {
                        SPListItem listItem = list.Items.Add();
                        GenerateItemData(listItem);
                        listItem.Update();

                        var message = string.Format("Added new list item [{0}]", i+1);
                        Log(message, MessageType.Info);
                    }
                }
            }
        }
        #endregion

        #region Validate Functions

        private bool ValidateNotZero(int number)
        {
            bool result = number != 0;
            return result;
        }

        private bool ValidateInteger(string number)
        {
            bool result = false;

            int numberOfFiles;
            bool numberOfFilesParse = int.TryParse(number, out numberOfFiles);
            if (numberOfFilesParse)
            {
                result = true;
            }

            return result;    
        }

        private bool ValidateSite()
        {
            bool result = false;
            if (_isSiteLoaded)
            {
                result = true;
            }
            else
            {
                Log(ErrorMessages.NoSiteLoaded, MessageType.Error);
            }
            return result;
        }

        private bool ValidateNumberOfSites(string number)
        {
            bool result = false;

            if (!string.IsNullOrEmpty(number))
            {
                try
                {
                    Convert.ToInt32(number);
                    result = true;
                }
                catch (Exception)
                {
                    Log(ErrorMessages.InvalidNumberOfSites, MessageType.Error);
                }
            }

            return result;
        }

        private bool ValidateCreateListItems()
        {
            bool result = true;

            //Check Library Selected
            if (listsListBox.SelectedItems.Count == 0)
            {
                Log(ErrorMessages.NoListSelected, MessageType.Error);
                result = false;
            }

            //Check # of files
            if (String.IsNullOrEmpty(numberOfListItemsTextBox.Text))
            {
                Log(ErrorMessages.NoNumberOfListItemsSet, MessageType.Error);
                result = false;
            }
            else
            {
                //Check # of files is a number that works
                if (!ValidateInteger(numberOfListItemsTextBox.Text))
                {
                    Log(ErrorMessages.InvalidNumberOfListItemsSet, MessageType.Error);
                    result = false;
                }
            }

            return result;
        }

        private bool ValidateCreateDocuments()
        {
            bool result = true;

            //Check File Date 
            if(dateRangeCheckBox.IsChecked == true)
            {
                if (!startDatePicker.SelectedDate.HasValue)
                {
                    Log(ErrorMessages.NoStartDateSet, MessageType.Error);
                    result = false;
                }
                if (!endDatePicker.SelectedDate.HasValue)
                {
                    Log(ErrorMessages.NoEndDateSet, MessageType.Error);
                    result = false;
                }

                if(endDatePicker.SelectedDate.HasValue && startDatePicker.SelectedDate.HasValue)
                {
                    if(DateTime.Compare(startDatePicker.SelectedDate.Value, endDatePicker.SelectedDate.Value) >= 0)
                    {
                        Log(ErrorMessages.InvalidTimeSpan, MessageType.Error);
                        result = false;
                    }
                }
            }
            else
            {
                if (!fileDatePicker.SelectedDate.HasValue)
                {
                    Log(ErrorMessages.NoFileDateSet, MessageType.Error);
                    result = false;
                }             
            }

            //Check File Size
            if (String.IsNullOrEmpty(fileSizeTexBox.Text))
            {
                Log(ErrorMessages.NoFileSizeSet, MessageType.Error);
                result = false;
            }
            else
            {
                //Check # of files is a number that works
                if (!ValidateInteger(fileSizeTexBox.Text))
                {
                    Log(ErrorMessages.InvalidFileSize, MessageType.Error);
                    result = false;
                }
                else
                {
                    if(!ValidateNotZero(Convert.ToInt32(fileSizeTexBox.Text)))
                    {
                        Log(ErrorMessages.NoZeroFileSize, MessageType.Error);
                        result = false;
                    }
                }
            }

            //Check Library Selected
            if (documentLibrariesListBox.SelectedItems.Count == 0)
            {
                Log(ErrorMessages.NoDocLibSelected, MessageType.Error);
                result = false;
            }

            //Check # of files
            if (String.IsNullOrEmpty(numberOfFilesTextBox.Text))
            {
                Log(ErrorMessages.NoNumberOfFilesSet, MessageType.Error);
                result = false;
            }
            else
            {
                //Check # of files is a number that works
                if (!ValidateInteger(numberOfFilesTextBox.Text))
                {
                    Log(ErrorMessages.InvalidNumberOfFiles, MessageType.Error);
                    result = false;
                }
            }

            //Check file types selected
            if(useAllTypesCheckBox.IsChecked != true)
            {
                bool fileTypeSelected = false;
                foreach (CheckBox checkBox in fileTypesListBox.Items)
                {
                    if (checkBox.IsChecked == true)
                    {
                        fileTypeSelected = true;
                        break;
                    }
                }
                if (!fileTypeSelected)
                {
                    Log(ErrorMessages.NoFileTypeSelected, MessageType.Error);
                    result = false;
                }
            }

            return result;
        }

        #endregion

        #region Events
        private void DateRangeCheckBoxChecked(object sender, RoutedEventArgs e)
        {
            fileDatePicker.IsEnabled = false;
            startDatePicker.IsEnabled = true;
            startDateLabel.IsEnabled = true;
            endDatePicker.IsEnabled = true;
            endDateLabel.IsEnabled = true;
        }

        private void DateRangeCheckBoxUnchecked(object sender, RoutedEventArgs e)
        {
            fileDatePicker.IsEnabled = true;
            startDatePicker.IsEnabled = false;
            startDateLabel.IsEnabled = false;
            endDatePicker.IsEnabled = false;
            endDateLabel.IsEnabled = false;
        }

        private void UseAllTypesCheckBoxChecked(object sender, RoutedEventArgs e)
        {
            fileTypesListBox.IsEnabled = false;
        }

        private void UseAllTypesCheckBoxUnchecked(object sender, RoutedEventArgs e)
        {
            fileTypesListBox.IsEnabled = true;
        }

        private void ShowHiddenLibrariesCheckBoxUnchecked(object sender, RoutedEventArgs e)
        {
            documentLibrariesListBox.Items.Clear();
            LoadDocumentLibraries(false);
        }

        private void ShowHiddenLibrariesCheckBoxChecked(object sender, RoutedEventArgs e)
        {
            documentLibrariesListBox.Items.Clear();
            LoadDocumentLibraries(true);
        }

        private void ShowHiddenListsCheckBoxUnchecked(object sender, RoutedEventArgs e)
        {
            listsListBox.Items.Clear();
            LoadLists(false);
        }
        
        private void ShowHiddenListsCheckBoxChecked(object sender, RoutedEventArgs e)
        {
            listsListBox.Items.Clear();
            LoadLists(true);
        }

        private void CreateDocumentsButtonClick(object sender, RoutedEventArgs e)
        {
            if (ValidateCreateDocuments())
            {
                const string func = "Creating Documents";
                Log(func, MessageType.Start);
                CreateDocuments();
                Log(func, MessageType.End);
            }
        }

        private void CreateListItemsClick(object sender, RoutedEventArgs e)
        {
            if (ValidateCreateListItems())
            {
                const string func = "Creating List Items";
                Log(func, MessageType.Start);
                CreateListItems();
                Log(func, MessageType.End);
            }
        }

        private void BackgroundWorkerOnDoWork(object sender, DoWorkEventArgs doWorkEventArgs)
        {
            CreateListItems();
        }

        private void CreateSitesButtonClick(object sender, RoutedEventArgs e)
        {
            string numberOfSites = numberOfSitesTextBox.Text;
            string numberOfLevels = levelsTextBox.Text;

            if (ValidateNumberOfSites(numberOfSites) && ValidateSite())
            {
                CreateSites();
            }
        }

        #endregion

        #region Load Functions
        private void LoadDocumentLibraries(bool showHidden)
        {
            SPListCollection lists = _site.spWeb.Lists;
            foreach (SPList list in lists)
            {
                if (list.BaseType == SPBaseType.DocumentLibrary)
                {
                    if (list.Hidden == true && !showHidden)
                        continue;
                    documentLibrariesListBox.Items.Add(list.Title);
                }
            }
        }

        private void LoadLists(bool showHidden)
        {
            SPListCollection lists = _site.spWeb.Lists;
            foreach (SPList list in lists)
            {
                if (list.BaseType == SPBaseType.GenericList)
                {
                    if (list.Hidden == true && !showHidden)
                        continue;
                    listsListBox.Items.Add(list.Title);
                }
            }
        }

        private void LoadFileTypes()
        {
            string fileTypesString = ConfigurationSettings.AppSettings.Get(Constants.SupportedFileTypes);
            string[] fileTypes = fileTypesString.Split(';');

            foreach (string fileType in fileTypes)
            {
                fileTypesListBox.Items.Add(new CheckBox {Content = fileType, IsChecked = false});
            }
        }

        private void LoadSiteButtonClick(object sender, RoutedEventArgs e)
        {
            if (!String.IsNullOrEmpty(siteUrlTextBox.Text))
            {
                LoadSite(siteUrlTextBox.Text);
            }
            else
            {
                Log(ErrorMessages.NoSiteUrl, MessageType.Info);
            }
        }

        private void LoadSite(string siteUrl)
        {
            try
            {
                ClearControls();

                //TODO: Do I try catch the site error in the class or herE?
                _site = new Site(siteUrl);
                Log(String.Format("Loaded {0}, {1}", _site.spWeb.Title, _site.spWeb.Url), MessageType.Info);
                StatusGood();
                _isSiteLoaded = true;

                PopulateSiteData();
            }
            catch (UriFormatException)
            {
                _isSiteLoaded = false;
                Log(ErrorMessages.InvalidUrl, MessageType.Error);
                StatusBad();
            }
            catch (FileNotFoundException)
            {
                _isSiteLoaded = false;
                Log(ErrorMessages.InvalidUrl, MessageType.Error);
                StatusBad();
            }
            catch (Exception ex)
            {
                _isSiteLoaded = false;
                Log(ex.ToString(), MessageType.Error);
                StatusBad();
            }
        }

        #endregion

        #region Nested type: MessageType

        private enum MessageType
        {
            Start,
            End,
            Warning,
            Error,
            Info
        }

        #endregion

 

 


    }
}